import anime from 'animejs'
import { edgeConfig } from '../config/edgeConfig'
import { sizeConfig } from '../config/sizeConfig'
import { BoolType, IModuleWithState } from '../types'
import {
    $,
    createDataValue,
    getCenterPoint,
    setDomBoolVal,
    toBinaryStr,
    toInt255,
} from '../utils'
import { bus1 } from './bus'
import { getInsCode, getInstruction } from './decoder'

interface IRamState {
    re: BoolType
    wr: BoolType
    selAddr: number
}

interface IRam extends IModuleWithState<IRamState> {
    data: number[]
    setRamData: (addr: number, value: number) => Promise<void>
}

// 把数组的长度设置成256
for (let i = RamInitialData.length; i < 256; i++) {
    RamInitialData[i] = 0
}

/**
 * 创建一个ramItem的dom
 */
function createRamItemDiv(addr: number, val: number): HTMLElement {
    const div = document.createElement('div')
    div.classList.add('ram-item')
    div.setAttribute('id', `ram-item-${addr}`)

    const addrDiv = document.createElement('div')
    addrDiv.classList.add('ram-item-addr')
    addrDiv.classList.add('data-item-val')
    addrDiv.dataset.value = addr + ''
    addrDiv.textContent = toBinaryStr(addr)

    const valDiv = document.createElement('div')
    valDiv.classList.add('ram-item-val')
    valDiv.classList.add('data-item-val')
    valDiv.dataset.value = val + ''
    valDiv.textContent = toBinaryStr(val)

    div.appendChild(addrDiv)
    div.appendChild(valDiv)

    return div
}

/**
 * 处理编辑ram逻辑
 */
function initEditRam() {
    // 给ram的dom注册点击事件
    $('.ram .content-2')?.addEventListener('click', () => {
        // 显示模态框
        $('.ram-edit')?.classList.remove('hide')
        // 初始化模态框内的文本域的内容
        const textArea = $('.ram-edit textarea') as any
        textArea.value = ram.data.reduce((prev, curr, index) => {
            let suf = ''
            const ins = getInstruction(curr)
            if (ins.isIns) {
                suf = ins.fullIns
            } else {
                suf = toBinaryStr(curr, 8, true)
            }
            return prev + index + ': ' + suf + '\n'
        }, '')
    })

    // 关闭按钮
    $('.ram-edit .close')?.addEventListener('click', () => {
        $('.ram-edit')?.classList.add('hide')
        const textArea = $('.ram-edit textarea') as any
        textArea.value = ''
    })

    // 保存按钮
    $('.ram-edit .save')?.addEventListener('click', () => {
        const textArea = $('.ram-edit textarea') as any
        const value = textArea.value
        // 以换行或‘，’分割
        const values = value.split(/,|\n/)
        values.forEach((item: string, index: number) => {
            item = item.trim()
            if (item === '') {
                return
            }
            // 判断item是否包含冒号
            const colonIndex = item.indexOf(':')
            let addr: string | number = index
            let val = item
            if (colonIndex !== -1) {
                // 包含冒号
                const splits = item.split(':')
                addr = splits[0].trim()
                val = splits[1].trim()
            }
            const addrInt = toInt255(addr + '')
            const valInt = toInt255(getInsCode(val))
            if (ram.data[addrInt] !== valInt) {
                ram.setRamData(addrInt, valInt)
            }
        })
        $('.ram-edit')?.classList.add('hide')
        textArea.value = ''
    })
}

/**
 * ram模块
 */
export const ram: IRam = {
    name: 'ram',
    data: [],
    state: {
        re: 0,
        wr: 1,
        selAddr: 0,
    },
    async setState(prop, value) {
        if (prop === 're' || prop === 'wr') {
            this.state[prop] = value
            setDomBoolVal(prop, this.state[prop] as BoolType)
        } else if (prop === 'selAddr') {
            // 将上一个选中的地址的样式去掉
            const oldSelAddr = this.state.selAddr
            this.state[prop] = value
            $(`#ram-item-${oldSelAddr}`)?.classList.remove('selected')
            $(`#ram-item-${value}`)?.classList.add('selected')
            // 让这个ram-item滑动到顶部
            const offsetTop = $(`#ram-item-${oldSelAddr}`)?.offsetTop
            if (offsetTop) {
                $('.ram .ram-items')?.scrollTo({
                    top: offsetTop - 20,
                    behavior: 'smooth',
                })
            }
        }
        return
    },
    async setRamData(addr: number, value: number) {
        this.data[addr] = value
        const valDiv = $(`#ram-item-${addr} .ram-item-val`)
        if (valDiv) {
            valDiv.textContent = toBinaryStr(value)
            valDiv.dataset.value = value + ''
        }
    },
    async rise() {
        // 在时钟上升沿
        if (this.state.re === 1) {
            // 当re为1时，把当前地址的数据给到1号总线
            const currIndex = this.state.selAddr
            const selValue = this.data[currIndex]
            const text = toBinaryStr(selValue)
            const data = createDataValue(selValue, text, {
                x: sizeConfig.ram.x + 60,
                y: sizeConfig.ram.y + 10 * (currIndex > 5 ? 5 : currIndex) + 10,
            })
            // 从初始位置到达ram的顶部后消失
            const timeline = anime.timeline({
                targets: data.dom,
                duration: (edgeConfig.time.rise + edgeConfig.time.high) * 0.05,
                easing: 'linear',
            })
            const ramTopCenter = getCenterPoint(sizeConfig.ram, 'top')
            return timeline
                .add({
                    translateX: ramTopCenter.x,
                    translateY: ramTopCenter.y - 10,
                })
                .add({
                    translateY: ramTopCenter.y - 10 - 34,
                    complete: () => {
                        bus1.setData(selValue, 'ram')
                        data.dom.remove()
                    },
                }).finished
        } else if (this.state.wr === 1) {
            // 当wr为1时，从1号总线中拿数据放到当前地址
            const currIndex = this.state.selAddr
            const busValue = bus1.getData()
            const text = toBinaryStr(busValue)
            const ramTopCenter = getCenterPoint(sizeConfig.ram, 'top')
            const data = createDataValue(busValue, text, {
                x: sizeConfig.ram.x + 60,
                y: ramTopCenter.y - 10 - 34,
            })
            // 从初始位置到达ram的顶部后消失
            const timeline = anime.timeline({
                targets: data.dom,
                duration: (edgeConfig.time.rise + edgeConfig.time.high) * 0.05,
                easing: 'linear',
            })
            return timeline.add({
                translateY:
                    sizeConfig.ram.y +
                    10 * (currIndex > 5 ? 5 : currIndex) +
                    10,
                complete: () => {
                    this.setRamData(currIndex, busValue)
                    data.dom.remove()
                },
            }).finished
        }
    },
    init() {
        // 设置re的初始值
        setDomBoolVal('re', this.state.re)
        // 设置wr的初始值
        setDomBoolVal('wr', this.state.wr)
        // 根据data的内容，初始化内存，显示到页面上
        const fragment = document.createDocumentFragment()
        for (let i = 0; i < RamInitialData.length; i++) {
            this.data[i] = RamInitialData[i]
            fragment.appendChild(createRamItemDiv(i, RamInitialData[i]))
        }
        $('.ram .ram-items')?.appendChild(fragment)
        // 设置当前选中的地址
        $(`#ram-item-${this.state.selAddr}`)?.classList.add('selected')
        // bus1.setData(this.data[this.state.selAddr], 'ram')
        initEditRam()
    },
}
